/*
 * @Author: xiaosihan
 * @Date: 2023-07-20 22:40:18
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-10-03 11:41:58
 */

import { GoodsData } from '#/type';
import utils from '@/utils/utils';
import { fabric } from 'fabric';
import { cloneDeep, get, isString, isUndefined } from 'lodash';
import { Color, Vector2 } from 'three';
import Transition from 'three-base/Transition';
import { degToRad } from 'three/src/math/MathUtils.js';
import FabricBarCode from './FabricBarCode';
import FabricCanvas from './FabricCanvas';
import FabricImage from './FabricImage';
import FabricMark from './FabricMark';
import FabricText from './FabricText';
import commonService from '@/api/services/commonService';
import apiClient from '@/api/apiClient';
import goodsUtils from '@/utils/goodsUtils';
import dayjs from 'dayjs';
import JsBarcode from "jsbarcode";

//  尺码打印布局编辑器
class SizePrintLayoutEditor {
  constructor() {
    window.sizePrintLayoutEditor = this;
  }

  //div容器元素
  divDom = (() => {
    const divDom = document.createElement('div');
    divDom.style.width = '750px';
    divDom.style.height = '500px';
    return divDom;
  })();

  // 画布
  canvas = (() => {
    const canvas = document.createElement('canvas');
    canvas.width = 750;
    canvas.height = 500;
    this.divDom.append(canvas);
    return canvas;
  })();

  // 4096画布
  canvas4096 = (() => {
    const canvas4096 = document.createElement('canvas');
    canvas4096.width = 4096;
    canvas4096.height = 4096;

    return canvas4096;
  })();

  // fabric 编辑器
  fabricCanvas = (() => {
    const fabricCanvas = new FabricCanvas(this.canvas);
    fabricCanvas.selection = true;
    fabricCanvas.skipOffscreen = false;
    return fabricCanvas;
  })();

  // fabric 编辑器
  fabricCanvas4096 = (() => {
    const fabricCanvas4096 = new FabricCanvas(this.canvas4096);
    return fabricCanvas4096;
  })();

  // 动画对象
  transition = (() => {
    const transition = new Transition({ angle: 0 });
    transition.setDuration(300);
    transition.onChange(({ angle }) => {
      const activeObject = this.fabricCanvas.getActiveObject();
      if (activeObject) {
        activeObject.angle = Math.floor(angle);
        this.render();
      }
    });
    return transition;
  })();

  //打印区域遮罩
  fabricMark = new FabricMark('');

  // 设置容器
  setContainer(div: HTMLDivElement | null) {
    if (div) {
      div.style.overflow = 'hidden';
      div.innerHTML = '';
      div.append(this.divDom);
    }
  }

  // 是否可以编辑
  selection = true;
  setSelection(selection: boolean) {
    this.selection = selection;
    this.fabricCanvas.selection = this.selection;
    const objects = this.fabricCanvas.getObjects();
    objects.map((o) => {
      o.selectable = this.selection;
    });
    if (!this.selection) {
      this.fabricCanvas.discardActiveObject();
    }
  }

  //微调选中的对象
  moveActiveObject(left: number, top: number) {
    const activeObj = this.fabricCanvas.getActiveObject();
    if (activeObj) {
      activeObj.set({
        top: (activeObj.top || 0) + top,
        left: (activeObj.left || 0) + left,
      });
      this.render();
    }
  }

  // 设置尺寸
  setWidth(width: number) {
    this.fabricCanvas.setWidth(width / 2); // 1500mm canvas 展示750px
    this.divDom.style.width = `${width / 2}px`;
  }

  setHeight(height: number) {
    this.fabricCanvas.setHeight(height / 2); // 1000mm canvas 展示500px
    this.divDom.style.height = `${height / 2}px`;
  }

  // 添加一个布局元素
  async addUv(name: string, svg: string) {
    // 没有就创建 有就修改
    let uv = this.fabricCanvas.getObjects().find((o) => o.name === name) as
      | fabric.Image
      | undefined;

    if (!uv) {
      uv = new fabric.Image('');
      uv.name = name;
      this.fabricCanvas.add(uv);
    } else {
      // return;
    }

    if (uv && uv.getSrc().replace(/https?:/, '') !== svg) {
      await new Promise((resolve) => {
        uv && uv.setSrc(svg, resolve, { crossOrigin: 'anonymous' });
      });

      uv.set({
        originX: 'center',
        originY: 'center',
        scaleX: (1 / 2.8346) * 0.5,
        scaleY: (1 / 2.8346) * 0.5,
        selectable: this.selection,
      });

      uv.set({
        left: this.fabricCanvas.getWidth() / 2,
        top: this.fabricCanvas.getHeight() / 2,
      });

      if (uv.type === 'barCode') {
        uv.setControlsVisibility({
          mtr: false,
          mt: false,
          mb: false,
          ml: false,
          mr: false,
          bl: true,
          br: true,
          tl: true,
          tr: true,
        });
      } else {
        uv.setControlsVisibility({
          mtr: false,
          mt: false,
          mb: false,
          ml: false,
          mr: false,
          bl: false,
          br: false,
          tl: false,
          tr: false,
        });
      }
      uv.setCoords();
      this.render();
    }
  }

  // 清空
  clear() {
    this.fabricCanvas.clear();
  }

  //  加载json 数据
  loadFromJSON(json: any, callback?: Function, reviver?: Function) {
    this.fabricCanvas.loadFromJSON(
      json,
      () => {
        const objects = this.fabricCanvas.getObjects();
        objects.map((o) => {
          o.set({
            originX: 'center',
            originY: 'center',
            selectable: this.selection,
          });
          if (o.type === 'barCode') {
            o.setControlsVisibility({
              mtr: false,
              mt: false,
              mb: false,
              ml: false,
              mr: false,
              bl: true,
              br: true,
              tl: true,
              tr: true,
            });
          } else {
            o.setControlsVisibility({
              mtr: false,
              mt: false,
              mb: false,
              ml: false,
              mr: false,
              bl: false,
              br: false,
              tl: false,
              tr: false,
            });
          }
        });

        //判断如果没有条形码对象就添加一个条形码对象
        const hasBarCode = objects.some((object) => object.type === 'barCode');

        if (!hasBarCode) {
          const fabricBarCode = new FabricBarCode();
          fabricBarCode.set({
            left: this.fabricCanvas.getWidth() / 2,
            top: this.fabricCanvas.getHeight() / 2,
          });
          this.fabricCanvas.add(fabricBarCode);
        }

        this.render();
        callback && callback();
      },
      reviver,
    );
  }

  // 数据导出
  toJSON() {
    return this.fabricCanvas.toJSON(['id', 'name', 'repeat']);
  }

  //设置选中元素的参数
  setActiveObjectData(data: Partial<fabric.Object>) {
    const activeObject = this.fabricCanvas.getActiveObject();
    if (activeObject) {
      for (let key in data) {
        if (key === 'left') {
          const halfWidth = activeObject.getScaledWidth() / 2;
          activeObject.set(key as keyof fabric.Object, data[key as keyof typeof data] + halfWidth);
        }
        if (key === 'top') {
          const halfHeight = activeObject.getScaledHeight() / 2;
          activeObject.set(key as keyof fabric.Object, data[key as keyof typeof data] + halfHeight);
        }
      }

      this.render();
    }
  }

  // 颠倒选中元素
  reverseActiveObject() {
    const activeObject = this.fabricCanvas.getActiveObject();
    if (activeObject) {
      this.transition
        .reset({ angle: activeObject.angle || 0 })
        .set({ angle: ((activeObject.angle || 0) + 180) % 360 });
    }
  }

  // 删除一个布局元素
  remove(name: string) {
    const uv = this.fabricCanvas.getObjects().find((o) => o.name === name);
    if (uv) {
      this.fabricCanvas.remove(uv);
      this.render();
    }
  }

  // 渲染画布
  render() {
    this.fabricCanvas.requestRenderAll();
  }

  //下载打印图纸需要的画布元素
  downPrintCanvas = document.createElement('canvas');
  downPrintFabricCanvas = new FabricCanvas(this.downPrintCanvas);

  //下载打纸文件
  async downPrint(
    goodsData: GoodsData,
    size: string,
    design_data: { [key: string]: Object },
    name: string,
  ) {
    const sizeConfig = goodsData.size.find((c) => c.name === this.fixSize(size))!;

    const scale = 5.9059 / window.devicePixelRatio;
    this.downPrintFabricCanvas.setWidth(sizeConfig.width * scale);
    this.downPrintFabricCanvas.setHeight(sizeConfig.height * scale);

    return await new Promise<void>((downPrintResolve) => {
      this.downPrintFabricCanvas.loadFromJSON(sizeConfig.printLayout, async () => {
        const objects = this.downPrintFabricCanvas.getObjects();

        for (let i = 0; i < objects.length; i++) {
          const { left, top, scaleX, scaleY, name = '', type } = objects[i] as fabric.Image;

          if (type === 'image') {
            const src = (objects[i] as fabric.Image).getSrc().replace(/^https?:/, '');

            if (/\.svg$/.test(src)) {
              await new Promise((resolve) => {
                fetch(src)
                  .then((response) => response.text())
                  .then((svgData) => {
                    // 在这里对 SVG 数据进行处理和修改 修改其中的文本变成对应的尺码文本
                    const color = new Color();
                    const colors = svgData.match(/#[a-zA-Z\d]{6}/g) || [];

                    // 去掉svg 中红色的线
                    for (let c of colors) {
                      color.set(c);
                      if (color.r > color.g + 0.5 && color.r > color.b + 0.5) {
                        svgData = svgData.replaceAll(c, `${c};display: none;`);
                      }
                    }

                    // 创建 Blob 对象
                    const blob = new Blob([svgData], { type: 'image/svg+xml' });
                    // 创建临时 URL 并设置给 img.src
                    const url = URL.createObjectURL(blob);
                    (objects[i] as fabric.Image).setSrc(url, resolve, { crossOrigin: 'anonymous' });
                  });
              });
            }
          }

          objects[i].set({
            originX: 'center',
            originY: 'center',
            left: left! * 2 * scale,
            top: top! * 2 * scale,
            scaleX: scaleX! * 2 * scale,
            scaleY: scaleY! * 2 * scale,
            objectCaching: true,
          });

          objects[i].shouldCache = () => true;
          //@ts-ignore
          objects[i].renderCache();

          const center = new Vector2(0, 0);
          const direction = new Vector2(0, 0);

          //@ts-ignore
          objects[i]._cacheContext.save();
          // 黑色轮廓绘制描边
          for (let deg = 0; deg < 360; deg += 10) {
            direction.set(5, 0);

            direction.rotateAround(center, degToRad(deg));
            //@ts-ignore
            objects[i]._cacheContext.shadowColor = '#ffffff';
            //@ts-ignore
            objects[i]._cacheContext.shadowOffsetX = direction.x;
            //@ts-ignore
            objects[i]._cacheContext.shadowOffsetY = direction.y;
            //@ts-ignore
            objects[i].drawObject(objects[i]._cacheContext);
          }
          //@ts-ignore
          objects[i]._cacheContext.restore();

          // 加载设计元素
          const fabricObjects = cloneDeep(design_data[name]);
          if (fabricObjects) {
            (get(fabricObjects, ['objects']) || []).map((o: fabric.Object) => {
              o.top! *= 4;
              o.left! *= 4;
              o.scaleX! *= 4;
              o.scaleY! *= 4;
            });
            await new Promise<void>((resolve) => {
              this.fabricCanvas4096.loadFromJSON(fabricObjects, async () => {
                const objects = this.fabricCanvas4096.getObjects();

                // 去掉 oss 参数下载高清图片
                for (const object of objects) {
                  object.objectCaching = false;
                  if (object.type === 'image') {
                    const originWidth = object.getScaledWidth();
                    const originHeight = object.getScaledHeight();
                    let src = (object as FabricImage).getSrc();
                    src = utils.ossSuffix(src); // 去掉图片地址的oss后缀
                    (object as FabricImage).imageSmoothingEnabled = false;
                    (object as FabricImage).print = true;
                    await new Promise<void>((resolve) => {
                      (object as FabricImage).setSrc(
                        src,
                        () => {
                          const { width = 10, height = 10 } = object;
                          object.set({
                            scaleX: originWidth / width,
                            scaleY: originHeight / height,
                          });
                          resolve();
                        },
                        { crossOrigin: 'anonymous' },
                      );
                    });
                  }
                }

                resolve();
              });
            });
            this.fabricCanvas4096.renderAll();

            //@ts-ignore
            const ctx = objects[i]._cacheContext! as CanvasRenderingContext2D;

            ctx.save();
            //@ts-ignore
            const { cacheWidth, cacheHeight, cacheTranslationX, cacheTranslationY } = objects[i];

            const maxSide = Math.floor(Math.max(cacheHeight, cacheWidth));

            ctx.resetTransform();
            ctx.globalCompositeOperation = 'destination-over';
            const offsetX = cacheTranslationX - cacheWidth * 0.5 + (cacheWidth - maxSide) * 0.5;
            const offsetY = cacheTranslationY - cacheHeight * 0.5 + (cacheHeight - maxSide) * 0.5;

            // 裁剪区域
            const component = goodsData.component.find((c) => c.key === name);
            if (component) {
              const {
                uv_3XS,
                uv_2XS,
                uv_XS,
                uv_S,
                uv_M,
                uv_L,
                uv_XL,
                uv_2XL,
                uv_3XL,
                uv_4XL,
                uv_5XL,
                uv_6XL,
                print_area_top,
                print_area_left,
                print_area_width,
                print_area_height,
                clip_print_area_left,
                clip_print_area_top,
                clip_print_area_width,
                clip_print_area_height,
              } = component;
              const uv_url =
                {
                  '3XS': uv_3XS,
                  '2XS': uv_2XS,
                  XS: uv_XS,
                  S: uv_S,
                  M: uv_M,
                  L: uv_L,
                  XL: uv_XL,
                  '2XL': uv_2XL,
                  '3XL': uv_3XL,
                  '4XL': uv_4XL,
                  '5XL': uv_5XL,
                  '6XL': uv_6XL,
                }[size] || '';

              // // 设置轮廓遮罩
              await this.fabricMark.setvPolygonBySvg(uv_url);

              // //设置矩形遮罩
              this.fabricMark.setRectMark(
                print_area_left,
                print_area_top,
                print_area_width,
                print_area_height,
              );
              this.fabricMark.setClipRectMark(
                clip_print_area_left,
                clip_print_area_top,
                clip_print_area_width,
                clip_print_area_height,
              );
              const ctx4096 = this.canvas4096.getContext('2d')!;
              this.fabricMark.filter(ctx4096);
            }

            ctx.drawImage(this.canvas4096, offsetX, offsetY, maxSide, maxSide);

            ctx.restore();
          }
        }

        this.downPrintFabricCanvas.renderAll();

        // 绘制白色的底色
        const printCtx = this.downPrintFabricCanvas.getContext();
        printCtx.save();
        printCtx.globalCompositeOperation = 'destination-over';
        printCtx.fillStyle = '#ffffff';
        printCtx.fillRect(0, 0, sizeConfig.width * scale, sizeConfig.height * scale);
        printCtx.restore();

        const base64 = this.downPrintCanvas.toDataURL('image/png', 1);

        const { changeDpiDataUrl } = await import('changedpi');
        var daurl150dpi = changeDpiDataUrl(base64, 150); // 设置150 的分辨率
        let saveLink = document.createElement('a');
        saveLink.download = `${name}.png`;
        saveLink.href = daurl150dpi;
        document.body.append(saveLink);
        saveLink.click();
        saveLink.remove();

        downPrintResolve();
      });
    });
  }

  // 这个方法是确保 front 字符串在 back 前面
  ensureFrontBeforeBack(arr: Array<string>) {
    const frontIndex = arr.indexOf('front');
    const backIndex = arr.indexOf('back');
    if (frontIndex === -1 || backIndex === -1) {
      return arr; // 如果不存在其中一个元素，直接返回原数组
    }
    if (frontIndex > backIndex) {
      // 交换两者的位置
      [arr[frontIndex], arr[backIndex]] = [arr[backIndex], arr[frontIndex]];
    }
    return arr;
  }

  //毫米转像素 150dpi
  mmToPx(mm: number) {
    // return mm * 2.8346;
    return mm * 5.9059;
  }

  //尺码修复
  fixSize(size: string) {
    const sizeConf = {
      "XXL": "2XL",
      "XXXL": "3XL",
      "XXXXL": "4XL",
      "XXXXXL": "5XL",
      "XXXXXXL": "6XL",
    };
    return sizeConf[size as keyof typeof sizeConf] || size;
  }

  // 获取直喷的图案
  async getDirectPrintBase64(
    goodsData: GoodsData,
    size: string,
    design_data: {
      [key: string]: { objects: Array<fabric.Object>; version: string; background: string };
    },
  ) {
    const base64s: Array<{ key: string; base64: string; width: number; height: number }> = [];

    let designDateKays = Object.keys(design_data).filter((k) =>
      goodsData.component.some((c) => c.key == k && c.enable),
    );

    designDateKays = this.ensureFrontBeforeBack(designDateKays);

    //遍历设计图
    for (let key of designDateKays) {
      const designDateObject = cloneDeep(design_data[key]);
      designDateObject.background = '';

      if (designDateObject.objects.length > 0) {
        const { modalSize } = goodsData;
        const com = goodsData.component.filter((c) => c.key === key)[0];
        //当前部位的打印区域
        const {
          uv_3XS,
          uv_2XS,
          uv_XS,
          uv_S,
          uv_M,
          uv_L,
          uv_XL,
          uv_2XL,
          uv_3XL,
          uv_4XL,
          uv_5XL,
          uv_6XL,
          print_area_height,
          print_area_left,
          print_area_top,
          print_area_width,
        } = com;
        const {
          clip_print_area_height,
          clip_print_area_left,
          clip_print_area_top,
          clip_print_area_width,
        } = com;

        let uv_url =
          uv_3XS ||
          uv_2XS ||
          uv_XS ||
          uv_S ||
          uv_M ||
          uv_L ||
          uv_XL ||
          uv_2XL ||
          uv_3XL ||
          uv_4XL ||
          uv_5XL ||
          uv_6XL;

        switch (modalSize) {
          case '3XS':
            uv_url = uv_3XS || uv_url;
            break;
          case '2XS':
            uv_url = uv_2XS || uv_url;
            break;
          case 'XS':
            uv_url = uv_XS || uv_url;
            break;
          case 'S':
            uv_url = uv_S || uv_url;
            break;
          case 'M':
            uv_url = uv_M || uv_url;
            break;
          case 'L':
            uv_url = uv_L || uv_url;
            break;
          case 'XL':
            uv_url = uv_XL || uv_url;
            break;
          case '2XL':
            uv_url = uv_2XL || uv_url;
            break;
          case '3XL':
            uv_url = uv_3XL || uv_url;
            break;
          case '4XL':
            uv_url = uv_4XL || uv_url;
            break;
          case '5XL':
            uv_url = uv_5XL || uv_url;
            break;
          case '6XL':
            uv_url = uv_6XL || uv_url;
            break;
          default:
            break;
        }

        // 获取uv 轮廓图的边长
        const sideLength = await new Promise<number>((resolve) => {
          const uv = new fabric.Image('');
          uv.setSrc(uv_url, () => {
            const { width, height } = uv.getElement();
            resolve(Math.max(width, height) * (1 / 2.8346));
          });
        });

        const canvasWidth = this.mmToPx(print_area_width); // 单片烫画纸的宽度
        const canvasHeight = this.mmToPx(print_area_height); // 烫画纸的高度
        const scale = canvasWidth / (print_area_width / sideLength); // 300dpi 的分辨率的缩放值

        // const offsetLeft = maxSide / 2.8346 * scale * print_area_left;
        // const offsetTop = maxSide / 2.8346 * scale * print_area_top;
        const offsetLeft = scale * (print_area_left / sideLength); // 计算每个元素距离设计区域的左偏移量
        const offsetTop = scale * (print_area_top / sideLength); // 计算每个元素距离设计区域的上偏移量

        this.downPrintFabricCanvas.setWidth(canvasWidth);
        this.downPrintFabricCanvas.setHeight(canvasHeight);

        await new Promise<void>((resolve) => {
          // 设计数据是按照1024的尺寸设计的,打印时要按照150dpi的大小来缩放
          (get(designDateObject, ['objects']) || []).map((o: fabric.Object & { src?: string }) => {
            o.top! *= scale / 1024;
            o.top! -= offsetTop;
            o.left! *= scale / 1024;
            o.left! -= offsetLeft;
            o.scaleX! *= scale / 1024;
            o.scaleY! *= scale / 1024;
            o.objectCaching = false;
          });
          // 在画布上加载设计元素
          this.downPrintFabricCanvas.loadFromJSON(designDateObject, async () => {
            const objects = this.downPrintFabricCanvas.getObjects();

            // 去掉 oss 参数下载高清图片
            for (const object of objects) {
              if (object.type === 'image') {
                const originWidth = object.getScaledWidth();
                const originHeight = object.getScaledHeight();
                let src = (object as FabricImage).getSrc();
                src = utils.ossSuffix(src); // 去掉图片地址的oss后缀
                (object as FabricImage).imageSmoothingEnabled = false;
                (object as FabricImage).print = true;
                await new Promise<void>((resolve) => {
                  (object as FabricImage).setSrc(
                    src,
                    () => {
                      const { width = 10, height = 10 } = object;
                      object.set({
                        scaleX: originWidth / width,
                        scaleY: originHeight / height,
                      });
                      resolve();
                    },
                    { crossOrigin: 'anonymous' },
                  );
                });
              }
            }

            resolve();
          });
        });

        this.downPrintFabricCanvas.renderAll();

        // 清理文字区域的图案
        const ctx = this.downPrintFabricCanvas.getContext();

        // 裁剪区域
        ctx.clearRect(
          ((clip_print_area_left - print_area_left) * scale) / sideLength,
          ((clip_print_area_top - print_area_top) * scale) / sideLength,
          (clip_print_area_width * scale) / sideLength,
          (clip_print_area_height * scale) / sideLength,
        );

        const base64 = this.downPrintCanvas.toDataURL('image/png', 1);

        base64s.push({ key, base64, width: canvasWidth, height: canvasHeight });
      }
    }
    return base64s;
  }

  // 获取局部打纸文件的blob数组
  async getPartPrintBase64s(
    goodsData: GoodsData,
    size: string,
    design_data: {
      [key: string]: { objects: Array<fabric.Object>; version: string; background: string };
    },
    order_id: number, // 订单号
    text: string, // 文本信息
    color: string, // 颜色
    printArea: 'front' | 'back' | 'double'
  ) {
    const base64s: Array<{ key: string; base64: string; width: number; height: number }> = [];

    let designDateKays = Object.keys(design_data).filter((k) => {
      const designDateObject = cloneDeep(design_data[k]);
      return goodsData.component.some((c) => c.key == k && c.enable) && (designDateObject.objects.length > 0);
    });

    designDateKays = this.ensureFrontBeforeBack(designDateKays);

    //遍历设计图
    for (let key of designDateKays) {
      const designDateObject = cloneDeep(design_data[key]);
      designDateObject.background = '';

      const { modalSize } = goodsData;
      const com = goodsData.component.filter((c) => c.key === key)[0];
      //当前部位的打印区域
      const {
        uv_3XS,
        uv_2XS,
        uv_XS,
        uv_S,
        uv_M,
        uv_L,
        uv_XL,
        uv_2XL,
        uv_3XL,
        uv_4XL,
        uv_5XL,
        uv_6XL,
        print_area_height,
        print_area_left,
        print_area_top,
        print_area_width,
      } = com;
      const {
        clip_print_area_height,
        clip_print_area_left,
        clip_print_area_top,
        clip_print_area_width,
      } = com;

      let uv_url =
        uv_3XS ||
        uv_2XS ||
        uv_XS ||
        uv_S ||
        uv_M ||
        uv_L ||
        uv_XL ||
        uv_2XL ||
        uv_3XL ||
        uv_4XL ||
        uv_5XL ||
        uv_6XL;

      switch (modalSize) {
        case '3XS':
          uv_url = uv_3XS || uv_url;
          break;
        case '2XS':
          uv_url = uv_2XS || uv_url;
          break;
        case 'XS':
          uv_url = uv_XS || uv_url;
          break;
        case 'S':
          uv_url = uv_S || uv_url;
          break;
        case 'M':
          uv_url = uv_M || uv_url;
          break;
        case 'L':
          uv_url = uv_L || uv_url;
          break;
        case 'XL':
          uv_url = uv_XL || uv_url;
          break;
        case '2XL':
          uv_url = uv_2XL || uv_url;
          break;
        case '3XL':
          uv_url = uv_3XL || uv_url;
          break;
        case '4XL':
          uv_url = uv_4XL || uv_url;
          break;
        case '5XL':
          uv_url = uv_5XL || uv_url;
          break;
        case '6XL':
          uv_url = uv_6XL || uv_url;
          break;
        default:
          break;
      }

      // 获取uv 轮廓图的边长
      const sideLength = await new Promise<number>((resolve) => {
        const uv = new fabric.Image('');
        uv.setSrc(uv_url, () => {
          const { width, height } = uv.getElement();
          resolve(Math.max(width, height) * (1 / 2.8346));
        });
      });

      const canvasWidth = this.mmToPx(print_area_width); // 单片烫画纸的宽度
      const canvasHeight = this.mmToPx(print_area_height + 30); // 烫画纸的高度
      const scale = canvasWidth / (print_area_width / sideLength); // 300dpi 的分辨率的缩放值

      // const offsetLeft = maxSide / 2.8346 * scale * print_area_left;
      // const offsetTop = maxSide / 2.8346 * scale * print_area_top;
      const offsetLeft = scale * (print_area_left / sideLength); // 计算每个元素距离设计区域的左偏移量
      const offsetTop = scale * (print_area_top / sideLength); // 计算每个元素距离设计区域的上偏移量

      this.downPrintFabricCanvas.setWidth(canvasWidth);
      this.downPrintFabricCanvas.setHeight(canvasHeight);

      await new Promise<void>((resolve) => {
        // 设计数据是按照1024的尺寸设计的,打印时要按照150dpi的大小来缩放
        (get(designDateObject, ['objects']) || []).map((o: fabric.Object & { src?: string }) => {
          o.top! *= scale / 1024;
          o.top! -= offsetTop;
          o.left! *= scale / 1024;
          o.left! -= offsetLeft;
          o.scaleX! *= scale / 1024;
          o.scaleY! *= scale / 1024;
          o.objectCaching = false;
        });
        // 在画布上加载设计元素
        this.downPrintFabricCanvas.loadFromJSON(designDateObject, async () => {
          const objects = this.downPrintFabricCanvas.getObjects();

          // 去掉 oss 参数下载高清图片
          for (const object of objects) {
            if (["Image", "image"].includes(object.type || "")) {
              const originWidth = object.getScaledWidth();
              const originHeight = object.getScaledHeight();
              let src = (object as FabricImage).getSrc();
              src = utils.ossSuffix(src); // 去掉图片地址的oss后缀
              (object as FabricImage).imageSmoothingEnabled = false;
              (object as FabricImage).print = true;
              await new Promise<void>((resolve) => {
                (object as FabricImage).setSrc(
                  src,
                  () => {
                    const { width = 10, height = 10 } = object;
                    object.set({
                      scaleX: originWidth / width,
                      scaleY: originHeight / height,
                    });
                    resolve();
                  },
                  { crossOrigin: 'anonymous' },
                );
              });
            }
          }

          resolve();
        });
      });

      this.downPrintFabricCanvas.renderAll();

      // 清理文字区域的图案
      const ctx = this.downPrintFabricCanvas.getContext();
      ctx.clearRect(
        0,
        scale * (print_area_height / sideLength),
        scale * (print_area_width / sideLength),
        400,
      );

      // 裁剪区域
      ctx.clearRect(
        ((clip_print_area_left - print_area_left) * scale) / sideLength,
        ((clip_print_area_top - print_area_top) * scale) / sideLength,
        (clip_print_area_width * scale) / sideLength,
        (clip_print_area_height * scale) / sideLength,
      );

      // 添加条码
      const barCode = new FabricBarCode();
      await barCode.setValue(`${order_id}-${size}`);
      barCode.set({
        originX: 'left',
        originY: 'top',
        left: 0,
        top: this.mmToPx(print_area_height) + 20,
        width: 500,
        height: 150,
      });
      //绘制条码
      barCode.render(ctx);

      //部位名称
      let comName = goodsData.component.find((c) => c.key === key)!.name;

      if (printArea === 'double') {
        comName = `双面/${comName}`;
      } else {
        comName = `仅${comName}`;
      }

      //绘制订单文字信息
      const textObject = new FabricText(`${text}_位置:${comName}`);

      textObject.set({
        originX: 'left',
        originY: 'top',
        left: 550,
        top: this.mmToPx(print_area_height) + 30,
        height: 150,
        fontSize: 50,
      });
      //绘制文字
      textObject.render(ctx);

      ctx.fillStyle = color || "#ffffff";
      ctx.fillRect(0, canvasHeight - 20, canvasWidth, 20);

      const base64 = this.downPrintCanvas.toDataURL('image/png', 1);

      base64s.push({ key, base64, width: canvasWidth, height: canvasHeight });
    }

    return base64s;
  }

  // 获取满版打纸文件的blob
  async getPrintBase64(
    goodsData: GoodsData,
    size: string,
    design_data: { [key: string]: Object },
    order_id: number, // 订单号
    threadColor: string = "#ffffff"//缝线的颜色
  ) {
    const sizeConfig = goodsData.size.find((c) => c.name === this.fixSize(size))!;

    const scale = 5.9059 / window.devicePixelRatio;
    this.downPrintFabricCanvas.setWidth(sizeConfig.width * scale);
    this.downPrintFabricCanvas.setHeight(sizeConfig.height * scale);

    return await new Promise<string>((downPrintResolve) => {
      this.downPrintFabricCanvas.loadFromJSON(sizeConfig.printLayout, async () => {
        const objects = this.downPrintFabricCanvas.getObjects();

        for (let i = 0; i < objects.length; i++) {
          const { left, top, scaleX, scaleY, name = '', type = '' } = objects[i] as fabric.Image;

          if (type === 'image') {
            const src = (objects[i] as fabric.Image).getSrc().replace(/^https?:/, '');

            if (/\.svg$/.test(src)) {
              await new Promise((resolve) => {
                fetch(src)
                  .then((response) => response.text())
                  .then((svgData) => {
                    // 在这里对 SVG 数据进行处理和修改 修改其中的文本变成对应的尺码文本
                    const color = new Color();
                    const colors = svgData.match(/#[a-zA-Z\d]{6}/g) || [];

                    // 去掉svg 中红色的线
                    for (let c of colors) {
                      color.set(c);
                      if (color.r > color.g + 0.5 && color.r > color.b + 0.5) {
                        svgData = svgData.replaceAll(c, `${c};display: none;`);
                      }
                    }

                    // 创建 Blob 对象
                    const blob = new Blob([svgData], { type: 'image/svg+xml' });
                    // 创建临时 URL 并设置给 img.src
                    const url = URL.createObjectURL(blob);
                    (objects[i] as fabric.Image).setSrc(url, resolve, { crossOrigin: 'anonymous' });
                  });
              });
            }
          }

          // 条码上的文字
          if (type === 'barCode') {
            const threadName = { "#ffffff": "白色", "#B4B5B9": "灰色", "#000000": "黑色" }[threadColor] || "白色";
            await (objects[i] as FabricBarCode).setValue(`${order_id}-${size}`, `-缝线:${threadName}`);
          }

          objects[i].set({
            originX: 'center',
            originY: 'center',
            left: left! * 2 * scale,
            top: top! * 2 * scale,
            scaleX: scaleX! * 2 * scale,
            scaleY: scaleY! * 2 * scale,
            objectCaching: true,
          });

          objects[i].shouldCache = () => true;
          //@ts-ignore
          objects[i].renderCache();

          const center = new Vector2(0, 0);
          const direction = new Vector2(0, 0);

          //@ts-ignore
          objects[i]._cacheContext.save();
          // 黑色轮廓绘制描边
          for (let deg = 0; deg < 360; deg += 10) {
            direction.set(5, 0);

            direction.rotateAround(center, degToRad(deg));
            //@ts-ignore
            objects[i]._cacheContext.shadowColor = '#ffffff';
            //@ts-ignore
            objects[i]._cacheContext.shadowOffsetX = direction.x;
            //@ts-ignore
            objects[i]._cacheContext.shadowOffsetY = direction.y;
            //@ts-ignore
            objects[i].drawObject(objects[i]._cacheContext);
          }
          //@ts-ignore
          objects[i]._cacheContext.restore();

          // 加载设计元素
          // console.log('design_data', design_data);

          const fabricObjects = cloneDeep(design_data[name]);

          if (fabricObjects) {
            // 设计数据是按照1024的尺寸设计的,打印时是按照4096来导出的所以要 * 4
            (get(fabricObjects, ['objects']) || []).map((o: fabric.Object) => {
              if (isUndefined(o.top)) {
                o.top = 0;
              }
              if (isUndefined(o.left)) {
                o.left = 0;
              }
              o.top! *= 4;
              o.left! *= 4;

              if (isUndefined(o.scaleX)) {
                o.scaleX = 1;
              }
              if (isUndefined(o.scaleY)) {
                o.scaleY = 1;
              }
              o.scaleX! *= 4;
              o.scaleY! *= 4;
            });
            
            // console.log('fabricObjects', fabricObjects);

            await new Promise<void>((resolve) => {
              this.fabricCanvas4096.loadFromJSON(fabricObjects, async () => {
                const objects = this.fabricCanvas4096.getObjects();

                // 去掉 oss 参数下载高清图片
                for (const object of objects) {
                  if (["Image", "image"].includes(object.type || "")) {
                    const originWidth = object.getScaledWidth();
                    const originHeight = object.getScaledHeight();
                    let src = (object as FabricImage).getSrc();
                    src = utils.ossSuffix(src); // 去掉图片地址的oss后缀
                    (object as FabricImage).imageSmoothingEnabled = false;
                    (object as FabricImage).print = true;
                    await new Promise<void>((resolve) => {
                      (object as FabricImage).setSrc(
                        src,
                        () => {
                          const { width = 10, height = 10 } = object;
                          object.set({
                            scaleX: originWidth / width,
                            scaleY: originHeight / height,
                          });
                          resolve();
                        },
                        { crossOrigin: 'anonymous' },
                      );
                    });
                  }
                }

                resolve();
              });
            });
            this.fabricCanvas4096.renderAll();
            const fabricCanvas4096Ctx = this.fabricCanvas4096.getContext();
            if (fabricCanvas4096Ctx) {
              fabricCanvas4096Ctx.save();
              fabricCanvas4096Ctx.fillStyle = get(fabricObjects, ['background']) || '#ffffff';
              fabricCanvas4096Ctx.globalCompositeOperation = 'destination-over';
              fabricCanvas4096Ctx.fillRect(0, 0, 4096, 4096);
              fabricCanvas4096Ctx.restore();
            }

            //@ts-ignore
            const ctx = objects[i]._cacheContext! as CanvasRenderingContext2D;

            ctx.save();
            //@ts-ignore
            const { cacheWidth, cacheHeight, cacheTranslationX, cacheTranslationY } = objects[i];

            const maxSide = Math.floor(Math.max(cacheHeight, cacheWidth));

            ctx.resetTransform();
            ctx.globalCompositeOperation = 'destination-over';
            const offsetX = cacheTranslationX - cacheWidth * 0.5 + (cacheWidth - maxSide) * 0.5;
            const offsetY = cacheTranslationY - cacheHeight * 0.5 + (cacheHeight - maxSide) * 0.5;

            // 裁剪区域
            const component = goodsData.component.find((c) => c.key === name);
            if (component) {
              const {
                uv_3XS,
                uv_2XS,
                uv_XS,
                uv_S,
                uv_M,
                uv_L,
                uv_XL,
                uv_2XL,
                uv_3XL,
                uv_4XL,
                uv_5XL,
                uv_6XL,
                print_area_top,
                print_area_left,
                print_area_width,
                print_area_height,
                clip_print_area_left,
                clip_print_area_top,
                clip_print_area_width,
                clip_print_area_height,
              } = component;
              const uv_url =
                {
                  '3XS': uv_3XS,
                  '2XS': uv_2XS,
                  XS: uv_XS,
                  S: uv_S,
                  M: uv_M,
                  L: uv_L,
                  XL: uv_XL,
                  '2XL': uv_2XL,
                  '3XL': uv_3XL,
                  '4XL': uv_4XL,
                  '5XL': uv_5XL,
                  '6XL': uv_6XL,
                }[this.fixSize(size)] || '';

              // // 设置轮廓遮罩
              await this.fabricMark.setvPolygonBySvg(uv_url);

              // //设置矩形遮罩
              this.fabricMark.setRectMark(
                print_area_left,
                print_area_top,
                print_area_width,
                print_area_height,
              );
              this.fabricMark.setClipRectMark(
                clip_print_area_left,
                clip_print_area_top,
                clip_print_area_width,
                clip_print_area_height,
              );
              const ctx4096 = this.canvas4096.getContext('2d')!;
              this.fabricMark.filter(ctx4096);
            }

            ctx.drawImage(this.canvas4096, offsetX, offsetY, maxSide, maxSide);

            ctx.restore();
          }
        }

        this.downPrintFabricCanvas.renderAll();

        // 绘制白色的底色
        const printCtx = this.downPrintFabricCanvas.getContext();
        printCtx.save();
        printCtx.globalCompositeOperation = 'destination-over';
        printCtx.fillStyle = '#ffffff';
        printCtx.fillRect(0, 0, sizeConfig.width * scale, sizeConfig.height * scale);
        printCtx.restore();

        const base64 = this.downPrintCanvas.toDataURL('image/png', 1);

        const { changeDpiDataUrl } = await import('changedpi');
        var daurl150dpi = changeDpiDataUrl(base64, 150); // 设置150 的分辨率

        downPrintResolve(daurl150dpi);
      });
    });
  }

  //烫画纸排版的canvas
  ironingPaperCanvas = (() => {
    const canvas = document.createElement('canvas');
    canvas.width = 100;
    canvas.height = 100;
    return canvas;
  })();

  // 订单详情数据Map
  orderDetailMap = new Map<number, any>();

  // 商品数据Map
  productMap = new Map<number, GoodsData>();

  //下载全部未打印过的商品打纸文件
  async downNoPrintOrderGoods(orderDetails: Array<any>) {
    // //需要打印的全部订单商品
    await import('@/myFabric/FabricImage');
    const JSZip = (await import('jszip')).default;
    const zip = new JSZip();

    const ids = orderDetails.map((orderDetail) => orderDetail.id);

    orderDetails.map((orderDetail) => {
      this.orderDetailMap.set(orderDetail.id, orderDetail);
    });

    // 取出 this.orderDetailMap 中所有订单的 ppId 字段并去重
    const ppIds = Array.from(new Set(orderDetails.map((orderDetail) => orderDetail.ppId)));

    //请求全部商品数据
    await Promise.all(ppIds.map((ppId) => {
      return new Promise<void>(async (resolve) => {
        let goodsData = await apiClient.get<any>({
          url: '/admin/pre-product/get',
          params: { domainId: ppId },
        });
        goodsData = goodsUtils.tojson(goodsData);
        this.productMap.set(ppId, goodsData);
        resolve();
      });
    }));

    //第一步导出打印所有满版打印文件
    for (let id of ids) {
      const orderDetail = this.orderDetailMap.get(id);
      let { designData, ppId, size, title, num, threadColor } = orderDetail;
      // 如果是字符串就转json
      designData = isString(designData) ? JSON.parse(designData) : designData;
      const goodsData = this.productMap.get(ppId)!;
      if (goodsData.fillType === 0) {

        // 0 是满版 1是局部
        // 遍历每个尺寸
        //如果商品类型是满版打印就导出满版图纸
        let base64 = await this.getPrintBase64(
          goodsData,
          size,
          designData || {},
          id, // 商品id
          threadColor
        );
        const dataURLPrefix = 'data:image/png;base64,';
        base64 = base64.replace(dataURLPrefix, '');
        const name = `满版印/${goodsData.materialName}_${goodsData.fabricDoorWidth}/${size}码_${num}件_${goodsData.name
          }.${new Date().valueOf()}.png`;
        // 存入zip包
        zip.file(name, base64, { base64: true });
      }
    }

    // 第二部导出所有烫画局部印前后片设计
    for (let id of ids) {
      const orderDetail = this.orderDetailMap.get(id);

      let { designData, ppId, size, title, num, printArea } = orderDetail;
      // 如果是字符串就转json
      designData = isString(designData) ? JSON.parse(designData) : designData;

      const goodsData = this.productMap.get(ppId)!;

      if (goodsData.fillType === 1 && goodsData.technology === "2") {
        if (
          Object.values(designData || {}).filter((data) => get(data, ['objects', 'length']) > 0)
            .length > 1
        ) {
          // 0 是满版 1是局部
          const base64s = await this.getPartPrintBase64s(
            goodsData,
            size,
            designData || {},
            id, // 商品id
            `${title}_${size}码_${orderDetail.color}\n款号:${goodsData.styleNumber}_共${num}件`, // 订单商品的信息
            orderDetail.colorValue,
            printArea
          );
          // 200mm*265mm 的局部印
          if (get(goodsData, ['component', 0, 'print_area_width']) === 200) {
            this.ironingPaperCanvas.width = base64s[0].height * 2;
            this.ironingPaperCanvas.height = base64s[0].width;
            // 把前后片设计图 绘制到canvas上
            const ctx = this.ironingPaperCanvas.getContext('2d')!;
            ctx.clearRect(0, 0, base64s[0].height * 2, base64s[0].width);
            // 绘制烫画纸左边
            await new Promise<void>((resolve, reject) => {
              const image = new Image();
              image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
              image.onload = () => {
                ctx.resetTransform();
                ctx.translate(0, base64s[0].width);
                ctx.rotate(Math.PI / -2);
                ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                ctx.drawImage(image, 0, 0);
                resolve();
              };
            });
            // 绘制烫画纸右边
            await new Promise<void>((resolve, reject) => {
              const image = new Image();
              image.src = base64s[1].base64; // 这里替换为您的 base64 图像数据
              image.onload = () => {
                ctx.resetTransform();
                ctx.translate(base64s[1].height * 2, 0);
                ctx.rotate(Math.PI / 2);
                ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                ctx.drawImage(image, 0, 0);
                resolve();
              };
            });
            // 280mm*350mm 的局部印
          } else if (get(goodsData, ['component', 0, 'print_area_width']) === 280) {
            this.ironingPaperCanvas.width = base64s[0].width * 2 + 236; // 236 是中间20mm间隔的像素宽度
            this.ironingPaperCanvas.height = base64s[0].height;
            // 把前后片设计图 绘制到canvas上
            const ctx = this.ironingPaperCanvas.getContext('2d')!;
            ctx.clearRect(0, 0, base64s[0].width * 2 + 236, base64s[0].height);
            // 绘制烫画纸左边
            await new Promise<void>((resolve, reject) => {
              const image = new Image();
              image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
              image.onload = () => {
                ctx.resetTransform();
                ctx.translate(0, 0);
                ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                ctx.drawImage(image, 0, 0);
                resolve();
              };
            });
            // 绘制烫画纸右边
            await new Promise<void>((resolve, reject) => {
              const image = new Image();
              image.src = base64s[1].base64; // 这里替换为您的 base64 图像数据
              image.onload = () => {
                ctx.resetTransform();
                ctx.translate(base64s[1].width + 236, 0);
                ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                ctx.drawImage(image, 0, 0);
                resolve();
              };
            });
          }
          const { changeDpiDataUrl } = await import('changedpi');
          let ironingPaperCanvasBase64 = this.ironingPaperCanvas.toDataURL('image/png', 1);
          let daurl150dpi = changeDpiDataUrl(ironingPaperCanvasBase64, 150); // 设置150的分辨率
          const dataURLPrefix = 'data:image/png;base64,';
          daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
          //存入zip包
          zip.file(`数码烫画/${num}件.${new Date().valueOf()}.png`, daurl150dpi, { base64: true });
        }
      }
    }

    // 第三步导出所有的单片设计的
    for (let id of ids) {
      const orderDetail = this.orderDetailMap.get(id);
      let { designData, ppId, size, title, num, color, printArea } = orderDetail;
      // 如果是字符串就转json
      designData = isString(designData) ? JSON.parse(designData) : designData;

      const goodsData = this.productMap.get(ppId)!;

      if (goodsData.fillType === 1 && goodsData.technology === "2") {
        if (Object.values(designData || {}).filter((data) => get(data, ['objects', 'length']) > 0).length === 1) {
          //数量大于1的就可以左右组合导出
          if (num > 1) {
            const base64s = await this.getPartPrintBase64s(
              goodsData,
              size,
              designData || {},
              id, // 商品id
              `${title}_${size}码_${orderDetail.color}\n款号:${goodsData.styleNumber}_共${num}件`, // 订单商品的信息
              orderDetail.colorValue,
              printArea
            );
            // 200mm*265mm 的局部印
            if (get(goodsData, ['component', 0, 'print_area_width']) === 200) {
              this.ironingPaperCanvas.width = base64s[0].height * 2;
              this.ironingPaperCanvas.height = base64s[0].width;
              // 把前后片设计图 绘制到canvas上
              const ctx = this.ironingPaperCanvas.getContext('2d')!;
              ctx.clearRect(0, 0, base64s[0].height * 2, base64s[0].width);
              // 绘制烫画纸左边
              await new Promise<void>((resolve, reject) => {
                const image = new Image();
                image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
                image.onload = () => {
                  // 绘制左边
                  ctx.resetTransform();
                  ctx.translate(0, base64s[0].width);
                  ctx.rotate(Math.PI / -2);
                  ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                  ctx.drawImage(image, 0, 0);
                  // 绘制右边
                  ctx.resetTransform();
                  ctx.translate(base64s[0].height * 2, 0);
                  ctx.rotate(Math.PI / 2);
                  ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                  ctx.drawImage(image, 0, 0);
                  resolve();
                };
              });
              // 280mm*350mm 的局部印
            } else if (get(goodsData, ['component', 0, 'print_area_width']) === 280) {
              this.ironingPaperCanvas.width = base64s[0].width * 2 + 236; // 236 是中间20mm间隔的像素宽度
              this.ironingPaperCanvas.height = base64s[0].height;
              // 把前后片设计图 绘制到canvas上
              const ctx = this.ironingPaperCanvas.getContext('2d')!;
              ctx.clearRect(0, 0, base64s[0].width * 2 + 236, base64s[0].height);
              // 绘制烫画纸左边
              await new Promise<void>((resolve, reject) => {
                const image = new Image();
                image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
                image.onload = () => {
                  // 绘制左边
                  ctx.resetTransform();
                  ctx.translate(0, 0);
                  ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                  ctx.drawImage(image, 0, 0);
                  // 绘制右边
                  ctx.resetTransform();
                  ctx.translate(base64s[0].width + 236, 0);
                  ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                  ctx.drawImage(image, 0, 0);
                  resolve();
                };
              });
            }
            const { changeDpiDataUrl } = await import('changedpi');
            let ironingPaperCanvasBase64 = this.ironingPaperCanvas.toDataURL('image/png', 1);
            let daurl150dpi = changeDpiDataUrl(ironingPaperCanvasBase64, 150); // 设置150的分辨率
            const dataURLPrefix = 'data:image/png;base64,';
            daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
            const printNum = Math.floor(num / 2);
            //存入zip包
            zip.file(`数码烫画/${printNum}件.${new Date().valueOf()}.png`, daurl150dpi, { base64: true });
          }
        }
      }
    }

    // 组合绘制导出打印位置
    let darwPosition = 'left' as 'left' | 'right';

    // 第四步导出 200mm*265mm 的单片设计的组合
    for (let id of ids) {
      const orderDetail = this.orderDetailMap.get(id);
      let { designData, ppId, size, title, num, color, printArea } = orderDetail;
      // 如果是字符串就转json
      designData = isString(designData) ? JSON.parse(designData) : designData;

      const goodsData = this.productMap.get(ppId)!;
      if (goodsData.fillType === 1 && goodsData.technology === "2") {
        if (
          Object.values(designData || {}).filter((data) => get(data, ['objects', 'length']) > 0)
            .length = 1
        ) {
          // 判断是单数则可以组合打印
          if (num % 2 === 1) {
            // 200mm*265mm 的局部印
            if (get(goodsData, ['component', 0, 'print_area_width']) === 200) {
              const base64s = await this.getPartPrintBase64s(
                goodsData,
                size,
                designData || {},
                id, // 商品id
                `${title}_${size}码_${orderDetail.color}\n款号:${goodsData.styleNumber}_共${num}件`, // 订单商品的信息
                orderDetail.colorValue,
                printArea
              );
              // 如果需要绘制到左边
              if (darwPosition === 'left') {
                this.ironingPaperCanvas.width = base64s[0].height * 2;
                this.ironingPaperCanvas.height = base64s[0].width;
                // 把前后片设计图 绘制到canvas上
                const ctx = this.ironingPaperCanvas.getContext('2d')!;
                ctx.clearRect(0, 0, base64s[0].height * 2, base64s[0].width);
                // 绘制烫画纸左边
                await new Promise<void>((resolve, reject) => {
                  const image = new Image();
                  image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
                  image.onload = () => {
                    ctx.resetTransform();
                    ctx.translate(0, base64s[0].width);
                    ctx.rotate(Math.PI / -2);
                    ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                    ctx.drawImage(image, 0, 0);
                    resolve();
                  };
                });
                // 标记下一次绘制到右边
                darwPosition = 'right';
              } else if (darwPosition === 'right') {
                // 绘制烫画纸左边
                await new Promise<void>((resolve, reject) => {
                  const ctx = this.ironingPaperCanvas.getContext('2d')!;
                  const image = new Image();
                  image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
                  image.onload = () => {
                    // 绘制右边
                    ctx.resetTransform();
                    ctx.translate(base64s[0].height * 2, 0);
                    ctx.rotate(Math.PI / 2);
                    ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                    ctx.drawImage(image, 0, 0);
                    resolve();
                  };
                });
                const { changeDpiDataUrl } = await import('changedpi');
                let ironingPaperCanvasBase64 = this.ironingPaperCanvas.toDataURL('image/png', 1);
                let daurl150dpi = changeDpiDataUrl(ironingPaperCanvasBase64, 150); // 设置150的分辨率
                const dataURLPrefix = 'data:image/png;base64,';
                daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
                //存入zip包
                zip.file(`数码烫画/1件.${new Date().valueOf()}.png`, daurl150dpi, { base64: true });
                // 标记下一次绘制到右边
                darwPosition = 'left';
              }
            }
          }
        }
      }
    }

    //组合打印时如果画布上有内容, 就导出画布上的内容到压缩包里面
    if (darwPosition === 'right') {
      const { changeDpiDataUrl } = await import('changedpi');
      let ironingPaperCanvasBase64 = this.ironingPaperCanvas.toDataURL('image/png', 1);
      let daurl150dpi = changeDpiDataUrl(ironingPaperCanvasBase64, 150); // 设置150的分辨率
      const dataURLPrefix = 'data:image/png;base64,';
      daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
      //存入zip包
      zip.file(`数码烫画/1件.${new Date().valueOf()}.png`, daurl150dpi, { base64: true });
    }
    // 280mm*350mm 组合绘制导出打印位置
    darwPosition = 'left';
    // 第五步导出 280mm*350mm 的单片设计的组合
    for (let id of ids) {
      const orderDetail = this.orderDetailMap.get(id);

      let { designData, ppId, size, title, num, color, printArea } = orderDetail;
      // 如果是字符串就转json
      designData = isString(designData) ? JSON.parse(designData) : designData;

      const goodsData = this.productMap.get(ppId)!;

      if (goodsData.fillType === 1 && goodsData.technology === "2") {
        // 如果有只有1个部位有设计数据就视为单面设计
        if (
          Object.values(designData || {}).filter((data) => get(data, ['objects', 'length']) > 0)
            .length === 1
        ) {
          // 判断是单数则可以组合打印
          if (num % 2 === 1) {
            // 280mm*350mm 的局部印
            if (get(goodsData, ['component', 0, 'print_area_width']) === 280) {
              const base64s = await this.getPartPrintBase64s(
                goodsData,
                size,
                designData || {},
                id, // 商品id
                `${title}_${size}码_${orderDetail.color}\n款号:${goodsData.styleNumber}_共${num}件`, // 订单商品的信息
                orderDetail.colorValue,
                printArea
              );
              // 如果需要绘制到左边
              if (darwPosition === 'left') {
                this.ironingPaperCanvas.width = base64s[0].width * 2 + 236; // 236 是中间20mm间隔的像素宽度
                this.ironingPaperCanvas.height = base64s[0].height;
                // 把前后片设计图 绘制到canvas上
                const ctx = this.ironingPaperCanvas.getContext('2d')!;
                ctx.clearRect(0, 0, base64s[0].width * 2 + 236, base64s[0].height);
                // 绘制烫画纸左边
                await new Promise<void>((resolve, reject) => {
                  const image = new Image();
                  image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
                  image.onload = () => {
                    ctx.resetTransform();
                    ctx.translate(0, 0);
                    ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                    ctx.drawImage(image, 0, 0);
                    resolve();
                  };
                });
                // 标记下一次绘制到右边
                darwPosition = 'right';
              } else if (darwPosition === 'right') {
                // 绘制烫画纸左边
                await new Promise<void>((resolve, reject) => {
                  const ctx = this.ironingPaperCanvas.getContext('2d')!;
                  const image = new Image();
                  image.src = base64s[0].base64; // 这里替换为您的 base64 图像数据
                  image.onload = () => {
                    // 绘制右边
                    ctx.resetTransform();
                    ctx.translate(base64s[0].width + 236, 0); // 236 是中间20mm间隔的像素宽度
                    ctx.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
                    ctx.drawImage(image, 0, 0);
                    resolve();
                  };
                });
                const { changeDpiDataUrl } = await import('changedpi');
                let ironingPaperCanvasBase64 = this.ironingPaperCanvas.toDataURL('image/png', 1);
                let daurl150dpi = changeDpiDataUrl(ironingPaperCanvasBase64, 150); // 设置150的分辨率
                const dataURLPrefix = 'data:image/png;base64,';
                daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
                //存入zip包
                zip.file(`数码烫画/1件.${new Date().valueOf()}.png`, daurl150dpi, { base64: true });
                // 标记下一次绘制到右边
                darwPosition = 'left';
              }
            }
          }
        }
      }
    }
    //组合打印时如果画布上有内容, 就导出画布上的内容到压缩包里面
    if (darwPosition === 'right') {
      const { changeDpiDataUrl } = await import('changedpi');
      let ironingPaperCanvasBase64 = this.ironingPaperCanvas.toDataURL('image/png', 1);
      let daurl150dpi = changeDpiDataUrl(ironingPaperCanvasBase64, 150); // 设置150的分辨率
      const dataURLPrefix = 'data:image/png;base64,';
      daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
      //存入zip包
      zip.file(`数码烫画/1件.${new Date().valueOf()}.png`, daurl150dpi, { base64: true });
    }

    // 数码直喷的需要的A3尺寸
    this.downPrintFabricCanvas.setWidth(this.mmToPx(297));
    this.downPrintFabricCanvas.setHeight(this.mmToPx(420));

    //下载数码直喷条码的canvas
    const barCodeCanvas = document.createElement('canvas');
    const barCodeCanvasCtx = barCodeCanvas.getContext('2d') as CanvasRenderingContext2D;
    barCodeCanvas.width = this.mmToPx(75);
    barCodeCanvas.height = this.mmToPx(130);

    const jspdf = await import('jspdf');
    // 打印条码用到的pdf文件
    const doc = new jspdf.jsPDF('p', 'mm', [75, 130]);
    let pdfimgNum = 0; // pdf图片的数量
    const comConfs = [
      {
        component: "front",
        comText: "前片",
        comCode: "0"
      },
      {
        component: "back",
        comText: "后片",
        comCode: "1"
      },
    ];

    // 第六步, 需要导出数码直喷的
    for (let i in ids) {
      const id = ids[i];
      const orderDetail = this.orderDetailMap.get(id);
      let { designData, ppId, size, title, num, color, colorValue, printArea, thumbnail } = orderDetail;

      thumbnail = JSON.parse(thumbnail);
      // printArea: 'front' | 'back' | 'double';
      // 如果是字符串就转json
      designData = isString(designData) ? JSON.parse(designData) : designData;

      const goodsData = this.productMap.get(ppId)!;

      //清空条码画布
      barCodeCanvasCtx.fillStyle = "#fff";
      barCodeCanvasCtx.fillRect(0, 0, barCodeCanvas.width, barCodeCanvas.height);

      //判断是不是局部印的数码直喷
      if (goodsData.fillType === 1 && goodsData.technology === "1") {

        for (let comConf of comConfs) {

          // 判断当前片是否需要打印
          if ([comConf.component, "double"].includes(printArea)) {

            // 创建一个临时的 SVG 元素
            var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            // 使用 JsBarcode 生成 SVG 图像
            JsBarcode(svg, `${id}-${comConf.comCode}`, {
              format: "CODE128", // 条码格式，这里使用 CODE128
              width: 6,
              fontSize: 50,
              displayValue: true, // 是否显示条码值
              text: `${id}-${comConf.comCode}`
            });
            // 将 SVG 图像转换为 XML 字符串
            var svgString = new XMLSerializer().serializeToString(svg);
            const img = new Image();
            await new Promise<void>((resolve, reject) => {
              // 当图像加载完成后，在 Canvas 上下文中绘制图像
              img.onload = () => {
                resolve();
              };
              var blob = new Blob([svgString], { type: "image/svg+xml" });
              var url = URL.createObjectURL(blob);
              img.src = url;
            });

            barCodeCanvasCtx.textBaseline = "top";
            barCodeCanvasCtx.font = "20px Arial";
            barCodeCanvasCtx.fillStyle = "#000";

            //把图片绘制到canvas上面
            if (comConf.component === "front") {
              barCodeCanvasCtx.fillStyle = colorValue || "#000000";
              barCodeCanvasCtx.fillRect(0, 0, this.mmToPx(2), this.mmToPx(50));
              barCodeCanvasCtx.drawImage(img, this.mmToPx(4), 0, this.mmToPx(67), this.mmToPx(20));
              barCodeCanvasCtx.fillStyle = "#000000";
              barCodeCanvasCtx.fillText(`名称 : ${title}`, this.mmToPx(4), this.mmToPx(20));
              barCodeCanvasCtx.fillText("工艺 : 数码直喷", this.mmToPx(4), this.mmToPx(24));
              barCodeCanvasCtx.fillText(`款号  : ${goodsData.styleNumber}`, this.mmToPx(4), this.mmToPx(28));
              barCodeCanvasCtx.fillText(`尺码 : ${size}`, this.mmToPx(4), this.mmToPx(32));
              barCodeCanvasCtx.fillText(`颜色 : ${color}`, this.mmToPx(4), this.mmToPx(36));
              barCodeCanvasCtx.fillText(`部位 : 前片`, this.mmToPx(4), this.mmToPx(40));

              const thumbnailimg = new Image();
              thumbnailimg.crossOrigin = "anonymous";
              await new Promise<void>((resolve, reject) => {
                thumbnailimg.onload = () => {
                  barCodeCanvasCtx.drawImage(thumbnailimg, this.mmToPx(40), this.mmToPx(20), this.mmToPx(30), this.mmToPx(30));
                  resolve();
                };
                if (thumbnail[0]) {
                  thumbnailimg.src = thumbnail[0];
                } else {
                  resolve();
                }
              });

            } else if (comConf.component === "back") {

              barCodeCanvasCtx.fillStyle = colorValue || "#000000";
              barCodeCanvasCtx.fillRect(0, this.mmToPx(54), this.mmToPx(2), this.mmToPx(50));
              barCodeCanvasCtx.drawImage(img, this.mmToPx(4), this.mmToPx(54), this.mmToPx(67), this.mmToPx(20));
              barCodeCanvasCtx.fillStyle = "#000000";
              barCodeCanvasCtx.fillText(`名称 : ${title}`, this.mmToPx(4), this.mmToPx(74));
              barCodeCanvasCtx.fillText("工艺 : 数码直喷", this.mmToPx(4), this.mmToPx(78));
              barCodeCanvasCtx.fillText(`款号  : ${goodsData.styleNumber}`, this.mmToPx(4), this.mmToPx(82));
              barCodeCanvasCtx.fillText(`尺码 : ${size}`, this.mmToPx(4), this.mmToPx(86));
              barCodeCanvasCtx.fillText(`颜色 : ${color}`, this.mmToPx(4), this.mmToPx(90));
              barCodeCanvasCtx.fillText(`部位 : 后片`, this.mmToPx(4), this.mmToPx(94));

              const thumbnailimg = new Image();
              thumbnailimg.crossOrigin = "anonymous";
              await new Promise<void>((resolve, reject) => {
                thumbnailimg.onload = () => {
                  barCodeCanvasCtx.drawImage(thumbnailimg, this.mmToPx(40), this.mmToPx(70), this.mmToPx(30), this.mmToPx(30));
                  resolve();
                };
                if (thumbnail[1]) {
                  thumbnailimg.src = thumbnail[1];
                } else {
                  resolve();
                }
              });

            }


          } else {

            //当前片没有
            if (comConf.component === "front") {
              barCodeCanvasCtx.textBaseline = "top";
              barCodeCanvasCtx.font = "20px Arial";
              barCodeCanvasCtx.fillStyle = "#000";
              barCodeCanvasCtx.fillText(`${id}-0-前片 无设计`, this.mmToPx(4), this.mmToPx(24));
            } else if (comConf.component === "back") {
              barCodeCanvasCtx.textBaseline = "top";
              barCodeCanvasCtx.font = "20px Arial";
              barCodeCanvasCtx.fillStyle = "#000";
              barCodeCanvasCtx.fillText(`${id}-1-后片 无设计`, this.mmToPx(4), this.mmToPx(78));
            }

          }
        }

        const { changeDpiDataUrl } = await import('changedpi');

        // let barCodeBase64 = barCodeCanvas.toDataURL('image/png', 1);
        // let daurl150dpi = changeDpiDataUrl(barCodeBase64, 150); // 设置150的分辨率
        // const dataURLPrefix = 'data:image/png;base64,';
        // daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
        for (let i = 0; i < num; i++) {
          if (pdfimgNum > 0) {
            doc.addPage(); // 从第二张图开始新增页面‌
          }
          pdfimgNum++;

          // 打印前片的数量
          if (["front", "double"].includes(printArea)) {
            barCodeCanvasCtx.clearRect(this.mmToPx(4), this.mmToPx(44), this.mmToPx(30), this.mmToPx(4));
            barCodeCanvasCtx.fillStyle = "#cccccc";
            // barCodeCanvasCtx.fillRect(this.mmToPx(4), this.mmToPx(44), this.mmToPx(30), this.mmToPx(4));
            barCodeCanvasCtx.fillStyle = "#000000";
            barCodeCanvasCtx.fillText(`数量 : ${i + 1}/${num}`, this.mmToPx(4.5), this.mmToPx(44.5));
          }

          // 打印后片的数量
          if (["back", "double"].includes(printArea)) {
            barCodeCanvasCtx.clearRect(this.mmToPx(4), this.mmToPx(98), this.mmToPx(30), this.mmToPx(4));
            barCodeCanvasCtx.fillStyle = "#cccccc";
            // barCodeCanvasCtx.fillRect(this.mmToPx(4), this.mmToPx(96), this.mmToPx(30), this.mmToPx(4));
            barCodeCanvasCtx.fillStyle = "#000000";
            barCodeCanvasCtx.fillText(`数量 : ${i + 1}/${num}`, this.mmToPx(4.5), this.mmToPx(98.5));
          }

          let barCodeBase64 = barCodeCanvas.toDataURL('image/png', 1);

          await new Promise<void>((resolve, reject) => {
            const img = document.createElement("img");
            img.crossOrigin = "anonymous";
            img.onload = () => {
              const pageWidth = doc.internal.pageSize.getWidth();
              const pageHeight = doc.internal.pageSize.getHeight();
              const ratio = Math.min(pageWidth / img.width, pageHeight / img.height);
              const imgWidth = img.width * ratio;
              const imgHeight = img.height * ratio;
              // 居中显示图片
              const x = (pageWidth - imgWidth) / 2;
              const y = (pageHeight - imgHeight) / 2;
              doc.addImage(img, 'PNG', x, y, imgWidth, imgHeight);
              resolve();
            }
            img.src = barCodeBase64;
          });

        }

        //条码存入zip包
        // zip.file(`数码直喷/条码/${num}件.${id}.png`, daurl150dpi.replace('data:image/png;base64,', ''), { base64: true });

        // 导出直喷图片存入zip包
        const base64s = await this.getDirectPrintBase64(
          goodsData,
          size,
          designData || {}
        );

        if (printArea === "double") {
          const [frontBase64, backBase64] = base64s;

          let daurl150dpi = changeDpiDataUrl(frontBase64.base64, 150); // 设置150的分辨率
          let dataURLPrefix = 'data:image/png;base64,';
          daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
          zip.file(`数码直喷/${id}-0.png`, daurl150dpi, { base64: true });

          daurl150dpi = changeDpiDataUrl(backBase64.base64, 150); // 设置150的分辨率
          daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
          zip.file(`数码直喷/${id}-1.png`, daurl150dpi, { base64: true });

        } else if (printArea === "front") {
          const [frontBase64] = base64s;
          let daurl150dpi = changeDpiDataUrl(frontBase64.base64, 150); // 设置150的分辨率
          let dataURLPrefix = 'data:image/png;base64,';
          daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
          zip.file(`数码直喷/${id}-0.png`, daurl150dpi, { base64: true });

        } else if (printArea === "back") {
          const [backBase64] = base64s;
          let daurl150dpi = changeDpiDataUrl(backBase64.base64, 150); // 设置150的分辨率
          let dataURLPrefix = 'data:image/png;base64,';
          daurl150dpi = daurl150dpi.replace(dataURLPrefix, '');
          zip.file(`数码直喷/${id}-1.png`, daurl150dpi, { base64: true });
        }

      }
    }

    //pdf 放到zip包里面
    if (pdfimgNum > 0) {
      const pdfBlob = doc.output('blob');
      zip.file('数码直喷条码.pdf', pdfBlob);
    }

    // 最后,下载zip文件
    zip.generateAsync({ type: 'blob' }).then((content) => {
      const downloadLink = document.createElement('a');
      downloadLink.href = URL.createObjectURL(content);
      downloadLink.download = `${dayjs().format('YYYY-MM-DD_HH-mm-ss')}.zip`;
      downloadLink.click();
    });


  }
}

const sizePrintLayoutEditor = (window.sizePrintLayoutEditor = new SizePrintLayoutEditor());

export default sizePrintLayoutEditor;
